package com.chuanke.ckfamily.service.finance.impl;

import com.chuanke.ckfamily.dao.base.CkUtil;
import com.chuanke.ckfamily.dao.finance.FamilyDayIncomeDao;
import com.chuanke.ckfamily.dao.finance.model.FamilyDayIncome;
import com.chuanke.ckfamily.dao.social.model.Family;
import com.chuanke.ckfamily.dao.social.model.FamilyCrule;
import com.chuanke.ckfamily.dao.social.model.FamilyMember;
import com.chuanke.ckfamily.dao.user.model.User;
import com.chuanke.ckfamily.service.base.FailCode;
import com.chuanke.ckfamily.service.common.CacheService;
import com.chuanke.ckfamily.service.common.impl.RedisLockUtil;
import com.chuanke.ckfamily.service.constant.BillType;
import com.chuanke.ckfamily.service.constant.FamilyDayIncomeType;
import com.chuanke.ckfamily.service.exception.CFException;
import com.chuanke.ckfamily.service.finance.BillService;
import com.chuanke.ckfamily.service.finance.FamilyDayIncomeService;
import com.chuanke.ckfamily.service.finance.PacketFinaceService;
import com.chuanke.ckfamily.service.social.FamilyCruleService;
import com.chuanke.ckfamily.service.social.FamilyFinanceService;
import com.chuanke.ckfamily.service.social.FamilyMemberService;
import com.chuanke.ckfamily.service.social.FamilyService;
import com.chuanke.ckfamily.service.user.UserService;
import com.weijie.core.BaseBiz;
import com.weijie.core.util.DateUtils;

import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional(rollbackFor = Exception.class)
public class FamilyDayIncomeServiceImpl extends BaseBiz<FamilyDayIncome, FamilyDayIncomeDao> implements FamilyDayIncomeService {
	private static final Logger log = LoggerFactory.getLogger(FamilyDayIncomeServiceImpl.class);
	@Autowired
	private FamilyMemberService familyMemberService;

	@Autowired
	private FamilyService familyService;

	@Autowired
	private UserService userService;

	@Autowired
	private FamilyCruleService familyCruleService;

	@Autowired
	private BillService billService;

	@Autowired
	private CacheService cacheService;

	@Autowired
	private FamilyFinanceService familyFinanceService;

	@Autowired
	private PacketFinaceService packetFinaceService;

	@Override
	public void addNewIncome(Long uid, Long money) throws CFException {
		if (money < 0) {
			throw new CFException(FailCode.PARAMS_ERROR);
		}

		if (userService.findById(uid) == null) {
			throw new CFException(FailCode.USER_NOT_EXIST);
		}

		FamilyMember familyMember = familyMemberService.findByUserId(uid);
		if (familyMember == null) {
			throw new CFException(FailCode.APP, "参数错误");
		}

		RedisLockUtil lock = null;
		try {
			String dayStr = DateUtils.format(new Date());
			lock = cacheService.getLock(CacheService.KEY_PREFIX.family_day_incom_.name() + familyMember.getFamily_id() + dayStr);
			FamilyDayIncome familyDayIncome = findDayIncome(familyMember.getFamily_id(), dayStr);
			updateFamilyDayIncome(familyDayIncome, CkUtil.sumMoney(familyDayIncome.getAll_money(), money), null, null, null, null, null);

			addMemberDevote(familyMember, money);
//			 familyFinanceService.addFamilyTotalCome(familyMember.getFamily_id(),money);

		} catch (Exception e) {
			e.printStackTrace();

		} finally {
			if (lock != null) {
				lock.unlock();
			}

		}
	}

	private FamilyDayIncome findDayIncome(Long fid, String day) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("fid", fid);
		param.put("date", day);
		FamilyDayIncome familyDayIncome = baseDao.getFamilyCountRecords(param);
		if (familyDayIncome == null) {
			familyDayIncome = new FamilyDayIncome();
			familyDayIncome.setFid(fid);
			familyDayIncome.setAll_money(0l);
			familyDayIncome.setCreate_time(DateUtils.dateToTimeStamp(new Date()));
			familyDayIncome.setI_date(day);
			familyDayIncome.setIs_assign(FamilyDayIncomeType.NO.getType());
			baseDao.add(familyDayIncome);
		}

		return familyDayIncome;
	}

	private void addMemberDevote(FamilyMember familyMember, Long money) throws CFException {
		FamilyMember update = new FamilyMember();
		update.setId(familyMember.getId());

		// 在cf_family_member表中添加家族成员贡献
		String date = DateUtils.format(new Date(familyMember.getUpdate_time().getTime()));
		// 添加今日收益
		if (DateUtils.format(new Date()).equals(date)) {
			update.setDevote(CkUtil.sumMoney(familyMember.getDevote(), money));

		} else {
			update.setDevote(money);

		}
		update.setUpdate_time(new Timestamp(System.currentTimeMillis()));
		update.setDevote_sum(CkUtil.sumMoney(familyMember.getDevote_sum(), money));
		familyMemberService.update(update);
	}

	@Override
	public void countIncome(String date) throws CFException {
		log.debug("==============开始分配家族收益=============>");
		Map<String, BigDecimal> allRule = getCountRule();
		BigDecimal leaderRule = allRule.get("leaderRule");
		BigDecimal superleaderRule = allRule.get("superleaderRule");
		BigDecimal redpacketRule = allRule.get("redpacketRule");
		log.debug("=================>获取分配规则   leaderRule={}, superleaderRule={}, redpacketRule={}", leaderRule, superleaderRule, redpacketRule);
		FamilyDayIncome income = null;
		List<Long> allFamilyId = familyService.getAllFamilyId();

		for (Long fid : allFamilyId) {
			RedisLockUtil lockUtil = null;
			try {
				lockUtil = cacheService.getLock(CacheService.KEY_PREFIX.family_day_incom_.name() + fid);
				income = getNeedCountRecords(fid, CkUtil.getYesterdayStr());
				if (income.getIs_assign() == null || income.getIs_assign() != FamilyDayIncomeType.YES.getType()) {
					countRecord(income, leaderRule, superleaderRule, redpacketRule);
				}

			} catch (Exception e) {
				e.printStackTrace();
				updateFamilyDayIncome(income, null, null, null, null, null, FamilyDayIncomeType.FAIL.getType());

			} finally {
				if (lockUtil != null) {
					lockUtil.unlock();
				}

			}
		}
	}

	/**
	 * 获取待分配资金列表
	 * 
	 * @param date
	 * @return
	 * @throws CFException 
	 * @throws Exception 
	 */
	private FamilyDayIncome getNeedCountRecords(Long fid, String date) throws CFException {
		Date tempDate = null;
		try {
			tempDate = DateUtils.strToDate(date);
		} catch (Exception e) {
			throw new CFException(FailCode.APP, "时间格式不正确");
		}

		date = DateUtils.sdfSimpleFormat(tempDate);
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("fid", fid);
		param.put("date", date);
		FamilyDayIncome familyDayIncome = baseDao.getFamilyCountRecords(param);
		if(familyDayIncome == null) {
			familyDayIncome = new FamilyDayIncome();
			familyDayIncome.setFid(fid);
			familyDayIncome.setAll_money(0L);
			familyDayIncome.setIs_assign(FamilyDayIncomeType.NO.getType());
			familyDayIncome.setI_date(date);
			familyDayIncome.setCreate_time(new Timestamp(tempDate.getTime()));

			baseDao.add(familyDayIncome);
		}
		return familyDayIncome;
	}

	/**
	 * 获取分配规则
	 * 
	 * @return
	 * @throws CFException
	 */
	private Map<String, BigDecimal> getCountRule() throws CFException {
		List<FamilyCrule> allRules = familyCruleService.findAll();
		BigDecimal leaderRule = null;
		BigDecimal superleaderRule = null;
		BigDecimal redpacketRule = null;
		Map<String, BigDecimal> result = new HashMap<String, BigDecimal>();

		if (allRules == null) {
			throw new CFException(FailCode.APP, "分配规则不存在");
		}

		for (FamilyCrule familyCrule : allRules) {
			switch (familyCrule.getRlevel()) {
			case FamilyCrule.SUPERLEADER:
				superleaderRule = new BigDecimal((float) familyCrule.getRvalue() / 100).setScale(2, BigDecimal.ROUND_HALF_UP);
				break;
			case FamilyCrule.LEADER:
				leaderRule = new BigDecimal((float) familyCrule.getRvalue() / 100).setScale(2, BigDecimal.ROUND_HALF_UP);
				break;
			case FamilyCrule.REDPACKET:
				if (familyCrule.getRvalue() == -1) {
					redpacketRule = new BigDecimal(-1);
				} else {

				}
				break;
			default:
				break;
			}
		}

		result.put("leaderRule", leaderRule);
		result.put("superleaderRule", superleaderRule);
		result.put("redpacketRule", redpacketRule);

		return result;
	}

	private void countRecord(FamilyDayIncome income, BigDecimal leaderRule, BigDecimal superleaderRule, BigDecimal redpacketRule) throws CFException {
		if (leaderRule == null || superleaderRule == null || redpacketRule == null) {
			throw new CFException(FailCode.APP, "");
		}

		// 获取家族id
		Long fid = income.getFid();
		// 获取家族
		Family family = familyService.findById(fid);
		if (family == null) {
			throw new CFException(FailCode.APP, "");
		}
		// 获取族长
		User owner = userService.findById(family.getOwner_user_id());
		if (owner == null || leaderRule == null) {
			throw new CFException(FailCode.APP, "");
		}

		// 获取待分配金额
		BigDecimal bd = new BigDecimal(income.getAll_money());
		Long leaderMoney = 0L;
		Long redpacketMoney = 0L;
		Long superMoney = 0L;
		Long bouns = 0L;

		// 分配给族长的金额
		leaderMoney = bd.multiply(leaderRule).longValue();
		long realyLeaderMoney = leaderMoney;
		if (leaderMoney < 1000L) {
			bouns = 1000 - leaderMoney;

			realyLeaderMoney = 1000L;
		}
		billService.addBill(family.getOwner_user_id(), realyLeaderMoney, BillType.FAMILY.getType(), null, "族长收益");

		// 没有上线，也要扣掉这百分之5
		superMoney = bd.multiply(superleaderRule).longValue();
		if (family.getSuper_id() != null && family.getSuper_id() != 0) {
			// 分配给上级的金额
			billService.addBill(family.getSuper_id(), superMoney.longValue(), BillType.FANSFAMILY.getType(), family.getOwner_user_id(), "粉丝家族收益");
		}

		// 分配给家族红包的金额
		redpacketMoney = income.getAll_money() - leaderMoney.longValue() - superMoney;
		// 更新处理结果
		updateFamilyDayIncome(income, null, realyLeaderMoney, superMoney, redpacketMoney, bouns, FamilyDayIncomeType.YES.getType());
		familyFinanceService.familyCount(fid, income.getAll_money(), realyLeaderMoney, superMoney, redpacketMoney);
		packetFinaceService.addForCount(fid, redpacketMoney);
	}

	@Override
	public FamilyDayIncome findByDate(Long fanilyId, String tday) {
		return baseDao.findByDate(fanilyId, tday);
	}

	@Override
	public void updateFamilyDayIncome(FamilyDayIncome familyDayIncome, Long allMoney, Long leaderMoney, Long superMoney, Long redpacketMoney, Long bouns, Integer isAssign) {
		FamilyDayIncome temp = new FamilyDayIncome();
		temp.setId(familyDayIncome.getId());
		temp.setAll_money(allMoney);
		temp.setLead_pay(leaderMoney);
		temp.setS_lead_pay(superMoney);
		temp.setPackbag_pay(redpacketMoney);
		temp.setIs_assign(isAssign);
		temp.setBouns(bouns);
		temp.setUpdate_time(new Timestamp(System.currentTimeMillis()));
		baseDao.update(temp);
	}
}